#ifndef STATE_H
#define STATE_H

#include "common/array.h"
#include "transition.h"

namespace state {

class State {
public:
	enum {SERVED, NOT_FOUND, EXIT};

	State(int id = -1, int maxTransitions = 1)
		: id_(id)
		, initial_(NULL)
		, active_(NULL)
		, transitions_(maxTransitions)
		, deleting_(false)
	{}	

	virtual ~State() {
		delete initial_;
		deleting_ = true;
		for (int i = 0; i < transitions_.getSize(); ++i) {
			if (transitions_[i]->state != NULL && !transitions_[i]->state->deleting_)
				delete transitions_[i]->state;
			delete transitions_[i];
		}
	}

	virtual void onEnter() = 0;

	int getId() const {
		return (active_ == NULL) ? id_ : active_->getId();
	}

	void setInitial(State *subState) {
		initial_ = subState;
	}

	void addTransition(int eventId, State *state) {
		transitions_.push(new Transition(eventId, state));
	}

	void enter(bool restored = false) {
		// TODO: implement state restoration
		onEnter();
		active_ = initial_;
		if (active_ != NULL)
			active_->enter();
	}

	int doEvent(int eventId, State *&newState) {
		int res = (active_ != NULL) ? active_->doEvent(eventId, newState) : NOT_FOUND;

		if (res == SERVED) {
			active_ = newState;
			newState = this;
			return SERVED;
		}
	
		for (int i = 0; i < transitions_.getSize(); ++i) {
			if (transitions_[i]->eventId == (res == EXIT ? -eventId : eventId)) {
				newState = transitions_[i]->state;
				if (newState == NULL)
					return EXIT;
				else {
					newState->enter();
					return SERVED;
				}
			}
		}

		return NOT_FOUND;
	}

	void getActiveEvents(Array<int> &events) {
		if (active_ != NULL)
			active_->getActiveEvents(events);

		for (int i = 0; i < transitions_.getSize(); ++i)
			events.push(transitions_[i]->eventId);
	}

	bool setSubstateById(int id) {
	// TODO: implement this for state restoration
		return false;
	}

private:
	const int id_;
	State *initial_;
	State *active_;
	Array<Transition *> transitions_;
	bool deleting_;
};

}

#endif






